using System;

using Sce.PlayStation.Core;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;
using Sce.PlayStation.HighLevel.Physics2D;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;
using Sce.PlayStation.HighLevel.UI;
using System.Collections.Generic;

namespace UWSGameJame
{
	public class GameScene : Sce.PlayStation.HighLevel.GameEngine2D.Scene
	{
		private BalloonScene physics;
		private Sce.PlayStation.HighLevel.UI.Scene uiScene;
		private Vector2 position;
		private List<Object> objectList;
		private FPS fps;
		private float width;
		private float height;
		private Vector2 difference;
		private BalloonGenerator bg;
		private Object floor;
		private int cannonCollTrig = 0;
		private int buildingsCollTrig = 0;
		private int floorCollTrig = 0;
		private Object buildings;
		private Object cannon;
		private bool movingRight = true;
		private bool inCannon = false;
		private bool fired = false;
		
		public GameScene ()
		{
			this.Camera.SetViewFromViewport ();
			physics = new BalloonScene ();
			
			width = Director.Instance.GL.Context.GetViewport ().Width;
			height = Director.Instance.GL.Context.GetViewport ().Height;
			
			difference = new Vector2 (0, 0);
			
			Sce.PlayStation.HighLevel.UI.Panel dialog = new Panel ();
			dialog.Width = width / 5;
			dialog.Height = height;
			
			ImageBox ib = new ImageBox ();
			ib.Width = width;
			ib.Image = new ImageAsset ("/Application/Resources/Textures/background.png", false);
			ib.Height = height;
			ib.SetPosition (0.0f, 0.0f);
                        
			Button buttonUI1 = new Button ();
			buttonUI1.Name = "buttonPlay";
			buttonUI1.Text = "Add Pipe";
			buttonUI1.Width = 100;
			buttonUI1.Height = 100;
			buttonUI1.Alpha = 0.8f;
			buttonUI1.SetPosition (0, 200.0f);
			buttonUI1.TouchEventReceived += (sender, e) => {
				TouchEvent touchEvent = e.TouchEvents.PrimaryTouchEvent;
				if (touchEvent.Type == TouchEventType.Down)
					addPlatform ();
				else if (touchEvent.Type == TouchEventType.Up) {
					foreach (Object o in objectList)
						o.unpick ();				
				}
			};
			
			dialog.AddChildLast (ib);
			dialog.AddChildLast (buttonUI1);
			
			uiScene = new Sce.PlayStation.HighLevel.UI.Scene ();
			uiScene.RootWidget.AddChildLast (dialog);
			UISystem.Initialize (Director.Instance.GL.Context);
			UISystem.SetScene (uiScene);
			
			objectList = new List<Object> ();
					
			bg = new BalloonGenerator (this, new Vector2 (100.0f, 500.0f));
				
			floor = new Object (width * 10, 10);
			floor.getPhysicsBody ().SetBodyTrigger ();
			floor.setPosition (new Vector2 (width / 2, 0.0f));
					
			floorCollTrig = physics.addBody (floor.getPhysicsShape (), floor.getPhysicsBody ());
			
			cannon = new Object ("Application/Resources/Textures/cannon.png", 200.0f);
			cannon.getPhysicsBody ().SetBodyTrigger ();
			
			cannon.setPosition (new Vector2 (50, 64));
			
			cannonCollTrig = physics.addBody (cannon.getPhysicsShape (), cannon.getPhysicsBody ());
			
			buildings = new Object ("Application/Resources/Textures/buildings.png", 200.0f);
			buildings.getPhysicsBody ().SetBodyTrigger ();
			buildings.setPosition (new Vector2 (this.width - 128, 128));
			
			this.AddChild (cannon.getSprite ());
			
			this.AddChild (buildings.getSprite ());
			this.startTheFire();

			fps = new FPS ();
			fps.Position = new Sce.PlayStation.Core.Vector2 (0, 0);
			this.AddChild (fps);
			
			buildingsCollTrig = physics.addBody (buildings.getPhysicsShape (), buildings.getPhysicsBody ());
			
			Scheduler.Instance.ScheduleUpdateForTarget (this, 0, false);
		}
		
		public override void Update (float dt)
		{
			base.Update (dt);
			
			try {
				UISystem.Update (Touch.GetData (0));
			} catch (System.Exception e) {
			}
			
			if (Input2.GamePad0.Left.Down) {
				this.Camera2D.SetViewFromWidthAndCenter (Director.Instance.GL.Context.GetViewport ().Width, 
					                                         new Vector2 (this.Camera.CalcBounds ().Center.X - 1.0f, this.Camera.CalcBounds ().Center.Y));
				fps.moveRight (-1.0f);
				difference.X -= 1.0f;
			}
			if (Input2.GamePad0.Right.Down) {
				this.Camera2D.SetViewFromWidthAndCenter (Director.Instance.GL.Context.GetViewport ().Width, 
					                                         new Vector2 (this.Camera.CalcBounds ().Center.X + 1.0f, this.Camera.CalcBounds ().Center.Y));
				fps.moveRight (1.0f);	
				difference.X += 1.0f;
				
			}
			if (Input2.GamePad0.Up.Down) {
				this.Camera2D.SetViewFromWidthAndCenter (Director.Instance.GL.Context.GetViewport ().Width, 
					                                         new Vector2 (this.Camera.CalcBounds ().Center.X, this.Camera.CalcBounds ().Center.Y + 1.0f));
				fps.moveUp (1.0f);
				difference.Y += 1.0f;

			}
			if (Input2.GamePad0.Down.Down) {
				if (this.Camera.CalcBounds ().Min.Y >= 0) {
					this.Camera2D.SetViewFromWidthAndCenter (Director.Instance.GL.Context.GetViewport ().Width, 
						                                         new Vector2 (this.Camera.CalcBounds ().Center.X, this.Camera.CalcBounds ().Center.Y - 1.0f));
					fps.moveUp (-1.0f);
					difference.Y -= 1.0f;
				}

			}
			if (Input2.GamePad0.Circle.Down) {
				Console.WriteLine ("O Pressed");
				foreach (Object o in objectList) {
					if (o.isPicked ()) {
						o.rotate (5.0f);
						break;
					}
				}
			}
			if (Input2.GamePad0.Square.Down) {
				Console.WriteLine ("S Pressed");
				foreach (Object o in objectList) {
					if (o.isPicked ()) {
						o.rotate (-5.0f);
						break;
					}
				}
			}			
		
			if (Input2.GamePad0.Cross.Down) {
				Console.WriteLine ("X Pressed");
				
				if (inCannon) {
					bg.fire ();
					inCannon = false;
					fired = true;
				} else {
					bg.release (physics);
				}
			}	
			
			uint[] coll_list = new uint[physics.getNumberOfBodies ()];
			
			int cannonColl = physics.QueryContactTrigger ((uint)cannonCollTrig, coll_list);
			int buildingColl = physics.QueryContactTrigger ((uint)buildingsCollTrig, coll_list);
			int floorColl = physics.QueryContactTrigger ((uint)floorCollTrig, coll_list);
			
			if (cannon.getPosition ().X + cannon.getSize ().X + 10 >= buildings.getPosition ().X - buildings.getSize ().X - 10 && movingRight) {
				movingRight = false;
			} else if (cannon.getPosition ().X < width / 4 && !movingRight) {
				movingRight = true;
			}
			
			if (movingRight) {
				cannon.moveRight (1.0f);
			} else {
				cannon.moveRight (-1.0f);
			}
			
			if (cannonColl > 0) {
				Console.WriteLine ("Cannon Collision");
				
				if (!fired && !inCannon)
					inCannon = true;
				
				if (!fired)
					bg.getBalloon ().setPosition (cannon.getPosition ());
			}
			
			if (floorColl > 0) {
				Console.WriteLine ("Floor Collision");
				if (!bg.getBalloon ().isPopped ()) {
					bg.getBalloon ().pop ();
					fired = false;
				}
			}
			
			if (buildingColl > 0) {
				Console.WriteLine ("Building Collision");
				if (!bg.getBalloon ().isPopped ()) {
					bg.getBalloon ().pop ();
					fired = false;
				}
			}
			
			foreach (var touchData in Touch.GetData(0)) {
				Vector2 trueTouch = new Vector2 ((int)((touchData.X + 0.5f) * Director.Instance.GL.Context.GetViewport ().Width) + difference.X, Director.Instance.GL.Context.GetViewport ().Height - (int)((touchData.Y + 0.5f) * Director.Instance.GL.Context.GetViewport ().Height) + difference.Y);
				position = trueTouch;	
				
				if (touchData.Status == TouchStatus.Up) {
					Console.WriteLine ("Up");
					foreach (Object o in objectList)
						o.unpick ();
				}
				
				if (touchData.Status == TouchStatus.Down) {
					Console.WriteLine ("Down");
					foreach (Object o in objectList) {
						if (o.isInside (trueTouch)) {
							Console.WriteLine ("Sprite Touch Registered at: " + trueTouch.ToString ());
							o.pick ();
							break;
						}
					}
				}
					
				if (touchData.Status == TouchStatus.Move) {
					Console.WriteLine ("Move");
					foreach (Object o in objectList) {
						if (o.isInside (trueTouch)) {
							Console.WriteLine ("Sprite Touch Registered at: " + trueTouch.ToString ());
							o.pick ();
						}
						if (o.isPicked ()) {
							o.setPosition (trueTouch);
							break;
						}
					}
				}
				
			}
			
			bg.update (this, physics);
			
			//We don't need these, but sadly, the Simulate call does.
			Vector2 dummy1 = new Vector2 ();
			Vector2 dummy2 = new Vector2 ();
            
			//Update the physics simulation
			physics.Simulate (-1, ref dummy1, ref dummy2);
		}
		
		public override void Draw ()
		{
			base.Draw ();
			UISystem.Render ();
		}
		
		public BalloonScene getPhysics ()
		{
			return this.physics;	
		}
		
		public void addPlatform ()
		{
			Object o = new Object ("Application/Resources/Textures/platform.png", PhysicsUtility.FltMax);
			o.setPosition (position);
			o.setPickable (true);
			objectList.Add (o);
			
			physics.addBody (o.getPhysicsShape (), o.getPhysicsBody ());
			
			o.addToScene (this);
			
			o.pick ();
		}
	
		public void startTheFire ()
		{
			float scale = 1.5f;

			Particles fire_node = new Particles (1000);
			ParticleSystem fire = fire_node.ParticleSystem;
			fire.TextureInfo = new TextureInfo (new Texture2D ("Application/Resources/Textures/fire.png", false));
			//		fire.BlendMode = BlendMode.PremultipliedAlpha;

			fire_node.Schedule (( dt ) => 

			{
				fire.Emit.Transform = fire_node.GetWorldTransform ();        
				fire.Emit.TransformForVelocityEstimate = fire_node.GetWorldTransform ();
				fire.RenderTransform = Director.Instance.CurrentScene.GetWorldTransform (); // most probably identity
			}

			, -1);

			fire_node.AdHocDraw += () => 

			{
				// debug draw the emission rectangle in pink

				Director.Instance.GL.SetBlendMode (Sce.PlayStation.HighLevel.GameEngine2D.Base.BlendMode.Additive);
				Director.Instance.DrawHelpers.SetColor (Colors.Red * 0.3f);
				Director.Instance.DrawHelpers.DrawBounds2 (Bounds2.QuadMinus1_1.Scale (fire.Emit.PositionVar, Sce.PlayStation.HighLevel.GameEngine2D.Base.Math._00));
			};

			fire.Emit.Velocity = new Vector2 (0.0f, 200.0f);
			fire.Emit.VelocityVar = new Vector2 (20.0f, 30.0f);
			fire.Emit.ForwardMomentum = 0.2f;
			fire.Emit.AngularMomentun = 0.0f;
			fire.Emit.LifeSpan = 2.4f;
			fire.Emit.WaitTime = 0.005f;
			float s = 0.25f;
			fire_node.Position = new Vector2 (0.0f, 0.0f - buildings.getSize().Y/2);
			fire.Emit.PositionVar = new Vector2 (buildings.getSize().X/2, 0.0f);
			fire.Emit.ColorStart = Colors.Red;
			fire.Emit.ColorStartVar = new Vector4 (0.0f, 0.0f, 0.0f, 0.0f);
			fire.Emit.ColorEnd = Colors.White;
			fire.Emit.ColorEndVar = new Vector4 (0.2f, 0.0f, 0.0f, 0.0f);
			fire.Emit.ScaleStart = 5.0f;
			fire.Emit.ScaleStartRelVar = 0.2f;
			fire.Emit.ScaleEnd = 10.0f;
			fire.Emit.ScaleEndRelVar = 0.2f;
			fire.Simulation.Fade = 0.3f;
			fire.Simulation.BrownianScale = 300.0f;

			buildings.getSprite().AddChild (fire_node);

			Particles smoke_node = new Particles (1000);
			ParticleSystem smoke = smoke_node.ParticleSystem;
			smoke.TextureInfo = new TextureInfo (new Texture2D ("Application/Resources/Textures/fire.png", false));

			smoke_node.Schedule (( dt ) => 

			{
				smoke.Emit.Transform = smoke_node.GetWorldTransform ();        
				smoke.Emit.TransformForVelocityEstimate = smoke_node.GetWorldTransform ();
				smoke.RenderTransform = Director.Instance.CurrentScene.GetWorldTransform (); // most probably identity
			}

			, -1);

			smoke_node.AdHocDraw += () => 

			{
				// debug draw the emission rectangle in pink

				Director.Instance.GL.SetBlendMode (Sce.PlayStation.HighLevel.GameEngine2D.Base.BlendMode.Additive);
				Director.Instance.DrawHelpers.SetColor (Colors.Grey10 * 0.3f);
				Director.Instance.DrawHelpers.DrawBounds2 (Bounds2.QuadMinus1_1.Scale (smoke.Emit.PositionVar, Sce.PlayStation.HighLevel.GameEngine2D.Base.Math._00));
			};

			smoke.Emit.Velocity = new Vector2 (0.0f, 200.0f);
			smoke.Emit.VelocityVar = new Vector2 (0.2f, 0.3f);
			smoke.Emit.ForwardMomentum = 0.2f;
			smoke.Emit.AngularMomentun = 0.0f;
			smoke.Emit.LifeSpan = 2.4f;
			smoke.Emit.WaitTime = 0.02f;
		
			smoke_node.Position = new Vector2 (0.0f, 0.0f);
			smoke.Emit.PositionVar = new Vector2 (buildings.getSize().X/2, 0.0f);
			smoke.Emit.ColorStart = Colors.Black;
			smoke.Emit.ColorStartVar = new Vector4 (0.0f, 0.0f, 0.0f, 0.0f);
			smoke.Emit.ColorEnd = Colors.Grey30;
			smoke.Emit.ColorEndVar = new Vector4 (0.2f, 0.0f, 0.0f, 0.0f);
			smoke.Emit.ScaleStart = 5.0f;
			smoke.Emit.ScaleStartRelVar = 0.2f;
			smoke.Emit.ScaleEnd = 15.0f;
			smoke.Emit.ScaleEndRelVar = 0.2f;
			smoke.Simulation.Fade = 0.3f;
			smoke.Simulation.BrownianScale = 300.0f;

			buildings.getSprite().AddChild (smoke_node);
		}
	}
}

